﻿#region << 文件说明 >>

/*----------------------------------------------------------------
 * 命名空间：Vampirewal.Core.RuleEngine.Interfaces
 * 唯一标识：72078514-916b-4ac4-8db5-61efa78592e5
 * 文件名：IVampirewalRuleEngine
 *
 * 创建者：杨程
 * 电子邮箱：235160615@qq.com
 * 创建时间：2023/10/11 15:22:58
 * 版本：V1.0.0
 * 描述：
 *
 * ----------------------------------------------------------------
 * 修改人：
 * 时间：
 * 修改说明：
 *
 * 版本：V1.0.1
 *----------------------------------------------------------------*/

#endregion << 文件说明 >>

namespace Vampirewal.Core.RuleEngine;

/// <summary>
/// 规则引擎服务
/// </summary>
public interface IVampirewalRuleEngine
{
    /// <summary>
    /// 同步执行
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="token"></param>
    /// <param name="data"></param>
    void Run<T>(string token, T? data) where T : class, new();

    /// <summary>
    /// 异步执行
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="token"></param>
    /// <param name="data"></param>
    /// <returns></returns>
    Task RunAsync<T>(string token, T? data) where T : class, new();
}

internal class VampirewalRuleEngine : IVampirewalRuleEngine
{
    public VampirewalRuleEngine(VampirewalRuleEngineOption _option, IServiceProvider service)
    {
        Option = _option;
        Service = service;
    }

    internal VampirewalRuleEngineOption Option { get; set; }

    internal IServiceProvider Service { get; set; }

    public void Run<T>(string token, T? data) where T : class, new()
    {
        if (Option.TypeDic.TryGetValue(token, out var ruleDic))
        {
            var VampirewalRule = Service.GetService(ruleDic) as IVampirewalRule<T>;

            VampirewalRuleBuilder<T> build = new VampirewalRuleBuilder<T>(data)
            {
                Service = this.Service,
                Option = this.Option,
            };

            VampirewalRule.Build(build);
        }
        else
        {
        }
    }

    public async Task RunAsync<T>(string token, T? data) where T : class, new()
    {
        await Task.Run(() =>
        {
            Run(token, data);
        });
    }
}

/// <summary>
/// 规则引擎配置
/// </summary>
public sealed class VampirewalRuleEngineOption
{
    public VampirewalRuleEngineOption()
    {
        TypeDic = new Dictionary<string, Type>();
    }

    internal Dictionary<string, Type> TypeDic { get; set; }

    public void RegisterRule<T, TData>(string token) where T : IVampirewalRule<TData> where TData : class, new()
    {
        if (!TypeDic.TryAdd(token, typeof(T)))
        {
            throw new Exception("token重复！");
        }
    }
}

/// <summary>
/// 规则执行返回值
/// </summary>
public sealed class VampirewalRuleExcuteResult
{
    public ExcutedState State { get; set; }

    /// <summary>
    /// 继续执行
    /// </summary>
    /// <returns></returns>
    public static VampirewalRuleExcuteResult Next()
    {
        return new VampirewalRuleExcuteResult()
        {
            State = ExcutedState.Success
        };
    }
}

/// <summary>
/// 执行完成之后的状态
/// </summary>
public enum ExcutedState
{
    Success = 0,
    Fail = 1,
}

/// <summary>
/// 步骤执行上下文
/// </summary>
/// <typeparam name="TData"></typeparam>
public interface IVampirewalRuleSetpContext<TData> where TData : class, new()
{
    /// <summary>
    /// 规则构造器
    /// </summary>
    IVampirewalRuleBuilder<TData> Builder { get; }

    /// <summary>
    /// IOC容器
    /// </summary>
    IServiceProvider Service { get; }

    /// <summary>
    /// 传递的数据源
    /// </summary>
    TData? Data { get; set; }

    /// <summary>
    /// 下一步执行需要的数据
    /// </summary>
    object NextNeedData { get; set; }
}

/// <summary>
/// 步骤执行上下文
/// </summary>
internal class VampirewalRuleSetpContext<TData> : IVampirewalRuleSetpContext<TData> where TData : class, new()
{
    /// <summary>
    /// 是否存在起点
    /// </summary>
    public bool HasStart { get; set; } = false;

    /// <summary>
    /// 是否已经结束
    /// </summary>
    public bool HasEnd { get; set; } = false;

    public TData? Data { get; set; }

    public IServiceProvider Service { get; internal set; }

    public object NextNeedData { get; set; }

    public IVampirewalRuleBuilder<TData> Builder { get; internal set; }
}